#include "mainwindow.h"
#include <QApplication>

#include "../dcmtk_include.h"


#include <QDir>
#include <QFile>
#include <QDebug>

#include <QTime>
#include <sys/time.h>

#include <cmath>
#include <math.h>

using namespace std;

struct SEGDCMINFO //数据属性
{
    int m_Height;   //高
    int m_Width;    //宽
    int m_Slice;    //切片数
    int m_WindowCenter; //窗位
    int m_WindowWidth; //窗宽
    float m_PixelSpace;    //像素间距
    int m_RescaleIntercept; //截距
    float m_SliceLocation1;//第一个切片层位置
    float m_SliceLocation2;//第二个切片层位置
    int m_InstanceNumber1;//第一个切片层数
    int m_InstanceNumber2;//第二个切片层数

    QString m_strSeriesUID;//(0020,000D) study UID
    QString m_strStudyUID;
};

#include<iostream>
using namespace std;

bool GetVolumnDataWin( QString FilePath,short **&VolumnData, SEGDCMINFO &DcmInfo);
bool DecodeDataset( DcmDataset *pDS, bool bRemoveOriginal );
bool SafeChooseRepresentation( void* pDataSet, int xfer, const void* pRepresentationParameter);


void ReadDicomFile();
void SaveEncodeDicom(DcmFileFormat& fileFormat);

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow m;
    m.show();
    return a.exec();

    QString patientName = "1.2.156.14702.1.1005.128.1.2018031511150382021361829/" ;

    QString rawDcmDir =  "./data/Source/ShenYangRawDcm/";
    QString CardiacDir = "./data/Source/ShenYangCardiacSegResultDcm/";
    QString VesselDir =  "./data/Source/ShenYangCoronarySegResultDcm/";

    short **RawVolume, **CardicVolume, **VesselVolume;

    DJDecoderRegistration::registerCodecs();//没有数据区大小的必须
    DJEncoderRegistration::registerCodecs();//选择JPEG传输协议不添加 报错 Pixel representation cannot be changed
    DJEncoderRegistration::registerCodecs(ECC_lossyRGB,EUC_default,false,0,0,0,
                                          true,ESS_444,false,false,0,0,0.0,0.0,
                                          0,0,0,0,true,false,false,false,true);
    //不同的传输协议要对应编码解码注册函数
    // initialize JPEG 2000 library
    //D2JPEG2000Library::initialize(); //需要 liblibjasperD.a

    // register global JPEG2K decompression codecs
    //D2EncoderRegistration::registerCodecs();

    // register global JPEG2K decompression codecs
    //D2DecoderRegistration::registerCodecs();

    // register JPEG-LS decompression codecs
    DJLSDecoderRegistration::registerCodecs();//需要liblibcharlsD.a

    // register JPEG-LS compression codecs
    DJLSEncoderRegistration::registerCodecs();

    // register RLE compression codec
    DcmRLEEncoderRegistration::registerCodecs();

    // register RLE decompression codec
    DcmRLEDecoderRegistration::registerCodecs();

    DJDecoderRegistration::registerCodecs();

    // register global JPEG compression codecs
    DJEncoderRegistration::registerCodecs();

    QString   RawPath = rawDcmDir + patientName  ;
    QString   CardicSegPath = CardiacDir + patientName  ;
    QString   VesselSegPath = VesselDir + patientName  ;

    SEGDCMINFO DcmInfo1;   SEGDCMINFO DcmInfo2;    SEGDCMINFO DcmInfo3;
    qDebug()<<"RawPath="<<RawPath<<endl;
    bool Status0 = GetVolumnDataWin(   RawPath ,  RawVolume,  DcmInfo1 );
    qDebug()<<"Status0="<<Status0<<endl;
    qDebug()<<"m_InstanceNumber1="<<DcmInfo1.m_InstanceNumber1<<endl;
    qDebug()<<"m_InstanceNumber2="<<DcmInfo1.m_InstanceNumber2<<endl;
    qDebug()<<"m_SliceLocation1="<<DcmInfo1.m_SliceLocation1<<endl;
    qDebug()<<"m_SliceLocation2="<<DcmInfo1.m_SliceLocation2<<endl;
    qDebug()<<"m_Height="<<DcmInfo1.m_Height<<endl;
    qDebug()<<"m_Width="<<DcmInfo1.m_Width<<endl;
    qDebug()<<"m_Slice="<<DcmInfo1.m_Slice<<endl;
    qDebug()<<"m_WindowCenter="<<DcmInfo1.m_WindowCenter<<endl;
    qDebug()<<"m_WindowWidth="<<DcmInfo1.m_WindowWidth<<endl;
    qDebug()<<"m_PixelSpace="<<DcmInfo1.m_PixelSpace<<endl;
    qDebug()<<"m_RescaleIntercept="<<DcmInfo1.m_RescaleIntercept<<endl;
    qDebug()<<"m_strSeriesUID="<<DcmInfo1.m_strSeriesUID<<endl;
    qDebug()<<"m_strStudyUID="<<DcmInfo1.m_strStudyUID<<endl;
    qDebug()<<" RawVolume: "<<RawVolume[0][0]<<endl;

    return 0;
}


bool GetVolumnDataWin( QString FilePath,short **&VolumnData, SEGDCMINFO &DcmInfo)
{
    //获取指定路径下所有文件信息
    QDir dir(FilePath);
    QStringList filter;
    filter<<"*.dcm";
    dir.setNameFilters(filter);
    QList<QFileInfo> fileInfo=QList<QFileInfo>(dir.entryInfoList(filter));
    qDebug() << "fileInfo count:" << fileInfo.count();
    //文件个数
    if (!fileInfo.count()){
        return false;
    }
    DcmInfo.m_Slice=fileInfo.count();

    //取第一个文件
    QString strPath=fileInfo.at(0).filePath();
    QByteArray ba = strPath.toLatin1();
    char *FileName = ba.data();
    DcmFileFormat fileFormat;
    OFCondition condition = fileFormat.loadFile(FileName);
    if(!condition.good()){
        return false;
    }
    //获取数据信息，宽、高、层间距、像素间距等
//    OFString OFSliceSpace, OFPixelSpace, OFHeight, OFWidth,OFRescaleIntercept,OFSliceLocation1,OFInstanceNumber1;
    OFString OFPixelSpace, OFHeight, OFWidth,OFSliceLocation1,OFInstanceNumber1,
            OFRescaleIntercept,OFWindowCenter, OFWindowWidth;
    fileFormat.getDataset()->findAndGetOFString(DCM_SliceLocation,OFSliceLocation1);
    fileFormat.getDataset()->findAndGetOFString(DCM_InstanceNumber,OFInstanceNumber1);
//    fileFormat.getDataset()->findAndGetOFString(DCM_SliceThickness, OFSliceSpace);
    fileFormat.getDataset()->findAndGetOFString(DCM_PixelSpacing, OFPixelSpace);
    fileFormat.getDataset()->findAndGetOFString(DCM_Rows, OFHeight);
    fileFormat.getDataset()->findAndGetOFString(DCM_Columns, OFWidth);
    fileFormat.getDataset()->findAndGetOFString(DCM_RescaleIntercept, OFRescaleIntercept);
    fileFormat.getDataset()->findAndGetOFString(DCM_WindowCenter, OFWindowCenter);
    fileFormat.getDataset()->findAndGetOFString(DCM_WindowWidth, OFWindowWidth);
//    DcmInfo.m_SliceSpace = atof(OFSliceSpace.c_str());
    DcmInfo.m_PixelSpace = atof(OFPixelSpace.c_str());
    DcmInfo.m_SliceLocation1=atof(OFSliceLocation1.c_str());
    DcmInfo.m_Height = atoi(OFHeight.c_str());
    DcmInfo.m_Width = atoi(OFWidth.c_str());
    DcmInfo.m_WindowCenter = atoi(OFWindowCenter.c_str());
    DcmInfo.m_WindowWidth = atoi(OFWindowWidth.c_str());
    DcmInfo.m_InstanceNumber1=atoi(OFInstanceNumber1.c_str());
    DcmInfo.m_RescaleIntercept=atoi(OFRescaleIntercept.c_str());

    OFString studyUid,seriesUid;
    fileFormat.getDataset()->findAndGetOFString(DCM_StudyInstanceUID, studyUid);
    fileFormat.getDataset()->findAndGetOFString(DCM_SeriesInstanceUID, seriesUid);
    DcmInfo.m_strStudyUID = QString(QLatin1String(studyUid.c_str()));
    DcmInfo.m_strSeriesUID = QString(QLatin1String(seriesUid.c_str()));;

    //取第二个文件
    QString strPath2=fileInfo.at(1).filePath();
    QByteArray ba2 = strPath2.toLatin1();
    char *FileName2 = ba2.data();
    DcmFileFormat fileFormat2;
    OFCondition condition2= fileFormat2.loadFile(FileName2);
    if(!condition2.good()){
        return false;
    }
    OFString OFSliceLocation2,OFInstanceNumber2;
    fileFormat2.getDataset()->findAndGetOFString(DCM_SliceLocation,OFSliceLocation2);
    fileFormat2.getDataset()->findAndGetOFString(DCM_InstanceNumber,OFInstanceNumber2);
    DcmInfo.m_SliceLocation2=atof(OFSliceLocation2.c_str());
    DcmInfo.m_InstanceNumber2=atoi(OFInstanceNumber2.c_str());

    //初始化体数据
    VolumnData = new short*[DcmInfo.m_Slice];
    for (int i = 0; i < DcmInfo.m_Slice; i++){
        VolumnData[i] = new short[DcmInfo.m_Height*DcmInfo.m_Width];
    }

    for (int i=0;i<DcmInfo.m_Slice;i++){
        //获取路径
        QString strPath=fileInfo.at(i).filePath();
        QByteArray ba = strPath.toLatin1();
        char *FileName = ba.data();
        //load
        DcmFileFormat fileFormat;
        OFCondition condition = fileFormat.loadFile(FileName);
        if(!condition.good()){
            return false;
        }

        //获取切片number
        OFString nstanceNumber;
        fileFormat.getDataset()->findAndGetOFString(DCM_InstanceNumber, nstanceNumber);

        int m_SliceNum = atoi(nstanceNumber.c_str());

        if(m_SliceNum>DcmInfo.m_Slice){
            return false;
        }

        //获取数据
        DcmDataset *data = fileFormat.getDataset();

        DcmXfer xferOrg( data->getOriginalXfer() );
        if ( xferOrg.isEncapsulated() )
        {
            bool bResult = DecodeDataset( data, true );
            //压缩数据处理
        }
        data->chooseRepresentation( EXS_LittleEndianExplicit, NULL );

        DcmElement* element = NULL;
        data->findAndGetElement(DCM_PixelData, element);
//        data->chooseRepresentation( EXS_LittleEndianExplicit, NULL );

        //Sint16* pixData16;
        //pDcmPixelData->getSint16Array( pixData16 );

        Uint16* pPixelData = NULL;
        element->getUint16Array( pPixelData );
//        Sint16* pixData16 = (Sint16*)pPixelData;

        for (int i = 0; i < DcmInfo.m_Height; i++){
            for (int j = 0; j < DcmInfo.m_Width; j++){
                VolumnData[m_SliceNum-1][i*DcmInfo.m_Width + j] =
                        pPixelData[i*DcmInfo.m_Width + j] + DcmInfo.m_RescaleIntercept;
            }
        }
    }
    return true;
}


bool DecodeDataset( DcmDataset *pDS, bool bRemoveOriginal ){
    // 获取原始DICOM传输语法
    DcmXfer xfer( pDS->getCurrentXfer() );
    // 如果是压缩的文件,则首先解压
    if ( xfer.isEncapsulated() ){
        bool				bResult = false;
        E_TransferSyntax	xferDecode = EXS_LittleEndianExplicit;

        bResult = SafeChooseRepresentation( pDS, xferDecode, NULL);
        // 清除原始压缩数据,将解压后的数据作为当前数据。
        if( bRemoveOriginal ){
            pDS->removeAllButCurrentRepresentations();
        }
        return bResult;
    }else{
        return true;
    }
}

bool SafeChooseRepresentation( void* pDataSet, int xfer, const void* pRepresentationParameter){
    //LockDicomCoding();
    DcmDataset *pDS = (DcmDataset*)pDataSet;
    //DcmXfer xferSynLossless( xferLossless );
    const DcmRepresentationParameter *rp = (DcmRepresentationParameter*)pRepresentationParameter;

    OFCondition		cond = EC_Normal;
    int				nTimes = 1;

    cond = pDS->chooseRepresentation( (E_TransferSyntax)xfer, rp );

    //// 如果不能转换为指定的传输协议，则直接返回
    //while( cond.bad() && ( nTimes < nRetryTimes || nRetryTimes == -1 ) )
    //{
    //	cond = pDS->chooseRepresentation( (E_TransferSyntax)xfer, rp );

    //	nTimes ++;
    //	//Sleep( nSpaceTime );
    //	Beep( 2000, 50 );
    //}

    //// 如果不能转换，则直接使用原文件
    //if ( pDS->canWriteXfer(xferLossless) )
    //{
    //	bResult = true;
    //}

    //UnlockDicomCoding();

    return !cond.bad();
}


void ReadDicomFile(){
    DcmFileFormat fileformat;
    OFCondition status = fileformat.loadFile("./data/IMG-0004-00020.dcm");
    if (status.good())
    {
      OFString StudyInstanceUID;
      if (fileformat.getDataset()->findAndGetOFString(DCM_StudyInstanceUID, StudyInstanceUID).good())
      {
        cout << "StudyInstanceUID: " << std::string(StudyInstanceUID.c_str()) << endl;
      } else{
        cerr << "Error: cannot access StudyInstanceUID!" << endl;
      }
    } else{
      cerr << "Error: cannot read DICOM file (" << status.text() << ")" << endl;
    }
}

void SaveEncodeDicom(DcmFileFormat& fileFormat){
    /** 保存dcm
    char uid[100];
    DcmFileFormat fileformat;
    DcmDataset *dataset = fileformat.getDataset();
    dataset->putAndInsertString(DCM_SOPClassUID, UID_SecondaryCaptureImageStorage);
    dataset->putAndInsertString(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT));
    dataset->putAndInsertString(DCM_PatientName, "Doe John");
    dataset->putAndInsertUint8Array(DCM_PixelData, pixelData, pixelLength);
    OFCondition status = fileformat.saveFile("test.dcm", EXS_LittleEndianExplicit);
    if (status.bad()){
      cerr << "Error: cannot write DICOM file (" << status.text() << ")" << endl;
    }*/

    //获取切片number
    OFString nstanceNumber;
    fileFormat.getDataset()->findAndGetOFString(DCM_InstanceNumber, nstanceNumber);

    OFString saveFileName = "./data/mysave/"+nstanceNumber+"_m.dcm";
    OFCondition status = fileFormat.saveFile(saveFileName, EXS_LittleEndianExplicit);
    if (status.bad()){
        std::cerr << "Error: cannot write DICOM file (" << status.text() << ")" << std::endl;
    }
}

